package weeny.util.io;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * All functions ignore hidden files/folders
 * Functions having "sub" prefix search only in the foler
 * Functions having "rec" prefix search recursively in every visible folder
 */
public class FileUtil {
	/**
	 * Give you a *NEW* list containing all strings match input regex from
	 * another candicate list.
	 */
	public static List<String> filter(String regex, List<String> names){
		if (regex ==  null) {
			return names;
		}
		List<String> result = new ArrayList<String>();
		Pattern p = Pattern.compile(regex);
		for(String name : names){
			Matcher m = p.matcher(new File(name).getName());
			if (m.matches()) {
				result.add(name);
			}
		}
		return result;
	}
	
	/**
	 * Give you all visible folders in the given folders, recursively!
	 */
	public static List<String> recFolders(File... dirs){
		List<String> result = new ArrayList<String>();
		for (File d : dirs){
			recFolders(d, result);
		}
		return result;
	}
	
	/**
	 * Give you all visible files in the given folders, recursively!
	 */
	public static List<String> recFiles(File... dirs){
		List<String> result = new ArrayList<String>();
		for (File d : dirs){
			recFiles(d, result);
		}
		return result;
	}
	
	/**
	 * Test if the file is hidden or has name starting with "."
	 */
	public static boolean isHidden(File file){
		return file.isHidden() || file.getName().startsWith(".");
	}
	/**
	 * Give you all visible files in the given folder, non-recursively!
	 */
	public static List<String> subFiles(String dir){
		return subFiles(new File(dir));
	}
	/**
	 * Give you all visible files in the given folder, non-recursively!
	 */
	public static List<String> subFiles(File dir){
		List<String> result = new ArrayList<String>();
		File[] files = dir.listFiles();
		for (File file : files) {
			if (file.isFile() && !isHidden(file)) {
				result.add(file.getAbsolutePath());
			}	
		}
		return result;
	}
	/**
	 * Give you all visible folders in the given folder, non-recursively!
	 */
	public static List<String> subFolders(String dir){
		return subFolders(new File(dir));
	}
	/**
	 * Give you all visible folders in the given folder, non-recursively!
	 */
	public static List<String> subFolders(File dir){
		List<String> result = new ArrayList<String>();
		File[] files = dir.listFiles();
		for (File file : files) {
			if (file.isDirectory() && !isHidden(file)) {
				result.add(file.getAbsolutePath());
			}
		}
		return result;
	}
	
	/**
	 * Give you all visible subfolders matching regex, non-recursively!
	 */
	public static List<String> subFoldersMatches(String regex, File dir){
		return filter(regex, subFolders(dir));
	}
	/**
	 * Give you all visible subfolders matching regex, non-recursively!
	 */
	public static List<String> recFoldersMatches(String regex, File dir){
		return filter(regex, recFolders(dir));
	}

	/**
	 * Give you all visible subfiles matching regex, non-recursively!
	 */
	public static List<String> subFilesMatches(String regex, File dir){
		return filter(regex, subFiles(dir));
	}
	/**
	 * Give you all visible subfiles matching regex, non-recursively!
	 */
	public static List<String> recFilesMatches(String regex, File dir){
		return filter(regex, recFiles(dir));
	}
	
	/**
	 * Give you all visible subfiles with extension, non-recursively!
	 */
	public static List<String> subFilesWithExt(String ext, File dir){
		String regex = ".*\\."+ext;
		return subFilesMatches(regex, dir);
	}
	/**
	 * Give you all visible subfiles with extension, recursively!
	 */
	public static List<String> recFilesWithExt(String ext, File dir){
		String regex = ".*\\."+ext;
		return recFilesMatches(regex, dir);
	}

	//recursive functions for folders and files
	private static void recFolders(File dir, List<String> result){
		if (dir.isFile() || isHidden(dir)) {
			return;
		}
		result.add(dir.getAbsolutePath());
		File[] files = dir.listFiles();
		for (File file2 : files) {
			recFolders(file2, result);
		}
	}
	private static void recFiles(File dir, List<String> result){
		if (dir.isFile() && !isHidden(dir)) {
			result.add(dir.getAbsolutePath());
		}
		else if(dir.isDirectory()){
			File[] files = dir.listFiles();
			for (File file2 : files) {
				recFiles(file2, result);
			}
		}
	}
}
